#include "spi.h"
#include "nrf_gpio.h"
#include <string.h>

/*!< timeout for getting rx bytes from slave */
#define TIMEOUT_COUNTER 0xFFFFFUL

#include "cfg_dbg.h"

#define LOG_ERROR(F, ...)
#define LOG_INFO(F, ...)
#define LOG_PRINTF(F, ...)

int spi_init(const spi_instance_t *inst)
{
    uint32_t config_mode;
    NRF_SPI_Type *SPIx;

    switch (inst->spix)
    {
    case NRF5x_SPI0:
        SPIx = NRF_SPI0;
        break;
    case NRF5x_SPI1:
        SPIx = NRF_SPI1;
        break;
    // case NRF5x_SPI2: SPIx = NRF_SPI2; break;
    default:

        return -1;
    }

    SPIx->ENABLE = (SPI_ENABLE_ENABLE_Disabled << SPI_ENABLE_ENABLE_Pos);

    /* Configure GPIO pins used for pselsck, pselmosi, pselmiso and pselss for SPI1*/
    nrf_gpio_cfg_output(inst->scl_pin);
    nrf_gpio_cfg_output(inst->mosi_pin);
    nrf_gpio_cfg_input(inst->miso_pin, NRF_GPIO_PIN_NOPULL);

    /* Configure pins, frequency and mode */
    SPIx->PSELSCK = inst->scl_pin;
    SPIx->PSELMOSI = inst->mosi_pin;
    SPIx->PSELMISO = inst->miso_pin;

    switch (inst->spi_freq)
    {
    case SPI_FREQ_125K:
        SPIx->FREQUENCY = (uint32_t)SPI_FREQUENCY_FREQUENCY_K125;
        break;
    case SPI_FREQ_500K:
        SPIx->FREQUENCY = (uint32_t)SPI_FREQUENCY_FREQUENCY_K500;
        break;
    case SPI_FREQ_1M:
        SPIx->FREQUENCY = (uint32_t)SPI_FREQUENCY_FREQUENCY_M1;
        break;
    case SPI_FREQ_2M:
        SPIx->FREQUENCY = (uint32_t)SPI_FREQUENCY_FREQUENCY_M2;
        break;
    case SPI_FREQ_4M:
        SPIx->FREQUENCY = (uint32_t)SPI_FREQUENCY_FREQUENCY_M4;
        break;
    case SPI_FREQ_8M:
        SPIx->FREQUENCY = (uint32_t)SPI_FREQUENCY_FREQUENCY_M8;
        break;
    default:
        return -1;
    }

    switch (inst->spi_mode)
    {
    case SPI_CPOL_0_CPHA_0:
        config_mode = (SPI_CONFIG_CPHA_Leading << SPI_CONFIG_CPHA_Pos) | (SPI_CONFIG_CPOL_ActiveHigh << SPI_CONFIG_CPOL_Pos);
        break;
    case SPI_CPOL_0_CPHA_1:
        config_mode = (SPI_CONFIG_CPHA_Trailing << SPI_CONFIG_CPHA_Pos) | (SPI_CONFIG_CPOL_ActiveHigh << SPI_CONFIG_CPOL_Pos);
        break;
    case SPI_CPOL_1_CPHA_0:
        config_mode = (SPI_CONFIG_CPHA_Leading << SPI_CONFIG_CPHA_Pos) | (SPI_CONFIG_CPOL_ActiveLow << SPI_CONFIG_CPOL_Pos);
        break;
    case SPI_CPOL_1_CPHA_1:
        config_mode = (SPI_CONFIG_CPHA_Trailing << SPI_CONFIG_CPHA_Pos) | (SPI_CONFIG_CPOL_ActiveLow << SPI_CONFIG_CPOL_Pos);
        break;
    default:
        return -1;
    }

    switch (inst->spi_order)
    {
    case SPI_ORDER_LSB:
        SPIx->CONFIG = (config_mode | (SPI_CONFIG_ORDER_LsbFirst << SPI_CONFIG_ORDER_Pos));
        break;
    case SPI_ORDER_MSB:
        SPIx->CONFIG = (config_mode | (SPI_CONFIG_ORDER_MsbFirst << SPI_CONFIG_ORDER_Pos));
        break;
    default:
        return -1;
    }

    SPIx->EVENTS_READY = 0U;

    /* Enable */
    SPIx->ENABLE = (SPI_ENABLE_ENABLE_Enabled << SPI_ENABLE_ENABLE_Pos);

    return 0;
}

int spi_off(const spi_instance_t *inst)
{
    // TODO 低功耗
    //    NRF_SPI_Type   *SPIx;

    //    //关SPI
    //    switch(inst->spix)
    //    {
    //        case NRF5x_SPI0: SPIx = NRF_SPI0; break;
    //        case NRF5x_SPI1: SPIx = NRF_SPI1; break;
    //        //case NRF5x_SPI2: SPIx = NRF_SPI2; break;
    //        default:

    //            return -1;
    //    }
    //    SPIx->ENABLE = (SPI_ENABLE_ENABLE_Disabled << SPI_ENABLE_ENABLE_Pos);

    //    //关GPIO
    //    nrf_gpio_cfg_default(inst->scl_pin);
    //    nrf_gpio_cfg_default(inst->mosi_pin);
    //    nrf_gpio_cfg_default(inst->miso_pin);

    return 0;
}

int spi_tx_rx(const spi_instance_t *inst, uint8_t *p_tx_buf, uint8_t *p_rx_buf, int len)
{
    uint32_t counter = 0;
    uint16_t number_of_txd_bytes = 0;
    NRF_SPI_Type *SPIx;

    switch (inst->spix)
    {
    case NRF5x_SPI0:
        SPIx = NRF_SPI0;
        break;
    case NRF5x_SPI1:
        SPIx = NRF_SPI1;
        break;
    // case NRF5x_SPI2: SPIx = NRF_SPI2; break;
    default:

        return -1;
    }

    while (number_of_txd_bytes < len)
    {
        SPIx->TXD = (uint32_t)(p_tx_buf[number_of_txd_bytes]);

        /* Wait for the transaction complete or timeout (about 10ms - 20 ms) */
        while ((SPIx->EVENTS_READY == 0U) && (counter < TIMEOUT_COUNTER))
        {
            counter++;
        }

        if (counter == TIMEOUT_COUNTER)
        {
            /* timed out, disable slave (slave select active low) and return with error */
            LOG_INFO("#Err SPI_ERR_TIMEOUT");
            return -2;
        }
        else
        {
            /* clear the event to be ready to receive next messages */
            SPIx->EVENTS_READY = 0U;
        }

        if (p_rx_buf == NULL)
        {
            //防止RXD中有数据无法接收新数据
            uint8_t dummy = (uint8_t)SPIx->RXD;
            dummy = dummy;
        }
        else
        {
            p_rx_buf[number_of_txd_bytes] = (uint8_t)SPIx->RXD;
        }

        number_of_txd_bytes++;
    };

    return 0;
}
